# Python 面向对象编程示例

print("=" * 50)
print("Python 面向对象编程")
print("""
1. 定义类和创建对象：类的基本语法和实例化
2. 类属性和实例属性：区分共享属性和独有属性
3. 方法类型：实例方法、类方法和静态方法
4. 继承：创建子类并继承父类的属性和方法
5. 封装：使用私有属性和方法控制访问
6. 多态：同一接口的不同实现
7. 特殊方法：魔术方法的使用
8. 类装饰器和属性：@property装饰器的使用
9. 抽象基类：定义抽象类和抽象方法
10. 类的继承关系：方法解析顺序(MRO)
""")
print("=" * 50)

# 1. 定义类和创建对象
print("\n1. 定义类和创建对象")
print("-" * 30)

class Person:
    # 类属性
    species = "Homo sapiens"

    # 构造方法
    def __init__(self, name, age):
        # 实例属性
        self.name = name
        self.age = age

    # 实例方法
    def introduce(self):
        return f"你好，我是 {self.name}，今年 {self.age} 岁。"

    # 另一个实例方法
    def have_birthday(self):
        self.age += 1
        return f"{self.name} 过了生日，现在 {self.age} 岁了！"

# 创建对象（实例化）
person1 = Person("张三", 25)
person2 = Person("李四", 30)

print(f"person1: {person1.introduce()}")
print(f"person2: {person2.introduce()}")

# 访问类属性
print(f"人类的学名: {Person.species}")

# 调用方法
print(person1.have_birthday())

# 2. 类属性和实例属性
print("\n\n2. 类属性和实例属性")
print("-" * 30)

class Student:
    # 类属性，所有实例共享
    school = "Python 编程学校"
    student_count = 0

    def __init__(self, name, grade):
        # 实例属性，每个实例独有
        self.name = name
        self.grade = grade
        # 每创建一个学生，学生计数加1
        Student.student_count += 1

# 创建学生实例
student1 = Student("小明", 85)
student2 = Student("小红", 92)

print(f"学生1: {student1.name}, 成绩: {student1.grade}")
print(f"学生2: {student2.name}, 成绩: {student2.grade}")
print(f"学校: {Student.school}")
print(f"学生总数: {Student.student_count}")

# 修改类属性
Student.school = "高级Python编程学校"
print(f"修改后的学校: {student1.school}")
print(f"修改后的学校: {student2.school}")

# 3. 方法类型
print("\n\n3. 方法类型")
print("-" * 30)

class Calculator:
    # 类属性
    version = "1.0"

    def __init__(self, name):
        self.name = name

    # 实例方法
    def add(self, a, b):
        return a + b

    # 类方法
    @classmethod
    def get_version(cls):
        return f"计算器版本: {cls.version}"

    # 静态方法
    @staticmethod
    def is_positive(number):
        return number > 0

# 使用实例方法
calc = Calculator("我的计算器")
print(f"使用 {calc.name} 计算: 3 + 5 = {calc.add(3, 5)}")

# 使用类方法
print(Calculator.get_version())

# 使用静态方法
print(f"5 是正数吗? {Calculator.is_positive(5)}")
print(f"-3 是正数吗? {Calculator.is_positive(-3)}")

# 4. 继承
print("\n\n4. 继承")
print("-" * 30)

# 基类
class Animal:
    def __init__(self, name, species):
        self.name = name
        self.species = species

    def make_sound(self):
        return "动物发出声音"

    def info(self):
        return f"我是 {self.name}，属于 {self.species} 种类"

# 派生类
class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name, "犬类")
        self.breed = breed

    # 重写父类方法
    def make_sound(self):
        return "汪汪汪！"

    # 新增方法
    def wag_tail(self):
        return f"{self.name} 摇尾巴"

class Cat(Animal):
    def __init__(self, name, color):
        super().__init__(name, "猫类")
        self.color = color

    # 重写父类方法
    def make_sound(self):
        return "喵喵喵！"

    # 新增方法
    def purr(self):
        return f"{self.name} 发出呼噜声"

# 创建动物实例
dog = Dog("旺财", "金毛")
cat = Cat("咪咪", "橘色")

print(dog.info())
print(f"品种: {dog.breed}")
print(f"叫声: {dog.make_sound()}")
print(dog.wag_tail())

print("\n" + cat.info())
print(f"颜色: {cat.color}")
print(f"叫声: {cat.make_sound()}")
print(cat.purr())

# 5. 封装
print("\n\n5. 封装")
print("-" * 30)

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        # 私有属性（通过前缀下划线约定）
        self._balance = balance
        # 更私有的属性（双下划线触发名称改写）
        self.__account_number = "123456789"

    # 公共方法
    def deposit(self, amount):
        if amount > 0:
            self._balance += amount
            return f"存款 {amount} 元，当前余额: {self._balance} 元"
        else:
            return "存款金额必须大于0"

    def withdraw(self, amount):
        if 0 < amount <= self._balance:
            self._balance -= amount
            return f"取款 {amount} 元，当前余额: {self._balance} 元"
        elif amount > self._balance:
            return "余额不足"
        else:
            return "取款金额必须大于0"

    # 属性访问器（getter）
    def get_balance(self):
        return self._balance

    # 属性修改器（setter）
    def set_balance(self, balance):
        if balance >= 0:
            self._balance = balance
        else:
            print("余额不能为负数")

# 使用银行账户
account = BankAccount("张三", 1000)
print(f"账户所有者: {account.owner}")
print(f"初始余额: {account.get_balance()} 元")

print(account.deposit(500))
print(account.withdraw(200))
print(f"当前余额: {account.get_balance()} 元")

# 尝试直接访问私有属性
print("\n尝试访问私有属性:")
print(f"account._balance = {account._balance}")  # 可以访问但不推荐
# print(account.__account_number)  # 这会报错
print(f"account._BankAccount__account_number = {account._BankAccount__account_number}")  # 通过名称改写访问

# 6. 多态
print("\n\n6. 多态")
print("-" * 30)

class Shape:
    def area(self):
        pass

    def perimeter(self):
        pass

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14159 * self.radius ** 2

    def perimeter(self):
        return 2 * 3.14159 * self.radius

# 多态示例
shapes = [
    Rectangle(5, 3),
    Circle(4),
    Rectangle(2, 8),
    Circle(3)
]

print("不同形状的面积和周长:")
for i, shape in enumerate(shapes, 1):
    print(f"形状 {i}: 面积 = {shape.area():.2f}, 周长 = {shape.perimeter():.2f}")

# 7. 特殊方法（魔术方法）
print("\n\n7. 特殊方法（魔术方法）")
print("-" * 30)

class Book:
    def __init__(self, title, author, pages):
        self.title = title
        self.author = author
        self.pages = pages

    # __str__ 方法，用于 str() 和 print()
    def __str__(self):
        return f"《{self.title}》 作者: {self.author}"

    # __repr__ 方法，用于 repr() 和调试
    def __repr__(self):
        return f"Book('{self.title}', '{self.author}', {self.pages})"

    # __len__ 方法，用于 len()
    def __len__(self):
        return self.pages

    # __eq__ 方法，用于 ==
    def __eq__(self, other):
        if isinstance(other, Book):
            return self.title == other.title and self.author == other.author
        return False

    # __lt__ 方法，用于 <
    def __lt__(self, other):
        if isinstance(other, Book):
            return self.pages < other.pages
        return NotImplemented

# 使用特殊方法
book1 = Book("Python编程", "张三", 300)
book2 = Book("Java编程", "李四", 400)
book3 = Book("Python编程", "张三", 350)  # 同一本书的不同版本

print(f"书籍信息: {book1}")
print(f"调试信息: {repr(book1)}")
print(f"页数: {len(book1)} 页")
print(f"两本书相同吗? {book1 == book2}")
print(f"两本书相同吗? {book1 == book3}")
print(f"book1 比 book2 短吗? {book1 < book2}")

# 8. 类装饰器和属性
print("\n\n8. 类装饰器和属性")
print("-" * 30)

class Temperature:
    def __init__(self, celsius=0):
        self._celsius = celsius

    # 属性装饰器，将方法变成属性
    @property
    def celsius(self):
        return self._celsius

    # setter 装饰器，允许设置属性值
    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("温度不能低于绝对零度")
        self._celsius = value

    # 只读属性
    @property
    def fahrenheit(self):
        return self._celsius * 9/5 + 32

    # 只读属性
    @property
    def kelvin(self):
        return self._celsius + 273.15

# 使用属性装饰器
temp = Temperature(25)
print(f"摄氏度: {temp.celsius}°C")
print(f"华氏度: {temp.fahrenheit}°F")
print(f"开尔文: {temp.kelvin}K")

# 使用 setter
temp.celsius = 30
print(f"更新后的摄氏度: {temp.celsius}°C")
print(f"更新后的华氏度: {temp.fahrenheit}°F")

# 9. 抽象基类
print("\n\n9. 抽象基类")
print("-" * 30)

from abc import ABC, abstractmethod

class Vehicle(ABC):
    def __init__(self, brand):
        self.brand = brand

    @abstractmethod
    def start(self):
        pass

    @abstractmethod
    def stop(self):
        pass

    # 具体方法
    def info(self):
        return f"这是 {self.brand} 品牌的交通工具"

class Car(Vehicle):
    def start(self):
        return f"{self.brand} 汽车启动了"

    def stop(self):
        return f"{self.brand} 汽车停止了"

class Bicycle(Vehicle):
    def start(self):
        return f"{self.brand} 自行车开始骑行了"

    def stop(self):
        return f"{self.brand} 自行车停止了"

# 创建具体类实例
car = Car("丰田")
bike = Bicycle("捷安特")

print(car.info())
print(car.start())
print(car.stop())

print(bike.info())
print(bike.start())
print(bike.stop())

# 10. 类的继承关系和方法解析顺序
print("\n\n10. 类的继承关系和方法解析顺序")
print("-" * 30)

class A:
    def method(self):
        print("A的方法")

class B(A):
    def method(self):
        print("B的方法")

class C(A):
    def method(self):
        print("C的方法")

class D(B, C):
    pass

# 查看方法解析顺序
print("类D的方法解析顺序:")
for cls in D.__mro__:
    print(f"  {cls}")

d = D()
d.method()  # 调用的是B的方法，因为B在方法解析顺序中排在C前面

print("\n" + "=" * 50)
print("面向对象编程示例结束")
print("=" * 50)
